package com.wk.code.wkserver.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wk.code.wkserver.constant.Constant;
import com.wk.code.wkserver.constant.EmailConstant;
import com.wk.code.wkserver.constant.NumberConstant;
import com.wk.code.wkserver.constant.enums.*;
import com.wk.code.wkserver.entity.*;
import com.wk.code.wkserver.exception.BizException;
import com.wk.code.wkserver.manager.AsyncTaskManager;
import com.wk.code.wkserver.mapper.SourceCodeMapper;
import com.wk.code.wkserver.request.admin.AdminSourceCodeRequest;
import com.wk.code.wkserver.request.admin.SourceCodeVerifyRequest;
import com.wk.code.wkserver.request.app.DemandVerifyRequest;
import com.wk.code.wkserver.request.app.SourceCodeRequest;
import com.wk.code.wkserver.request.base.BasePageRequest;
import com.wk.code.wkserver.response.admin.AdminSourceCodeDetailResponse;
import com.wk.code.wkserver.response.admin.DemandResponse;
import com.wk.code.wkserver.response.admin.SourceCodeResponse;
import com.wk.code.wkserver.response.app.AppSourceCodeResponse;
import com.wk.code.wkserver.response.app.SourceCodeDetailResponse;
import com.wk.code.wkserver.response.app.SourceCodeListResponse;
import com.wk.code.wkserver.response.base.PageInfo;
import com.wk.code.wkserver.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wk.code.wkserver.utils.DateUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author wq
 * @since 2021-08-15
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class SourceCodeServiceImpl extends ServiceImpl<SourceCodeMapper, SourceCode> implements ISourceCodeService {

    @Resource
    private IUserService userService;

    @Resource
    private IAdminVerifyRecordService adminVerifyRecordService;

    @Resource
    private ITechTypeService techTypeService;

    @Resource
    private IMailService mailService;

    @Resource
    private ISysUserService sysUserService;

    @Resource
    private IUserInfoService userInfoService;

    @Resource
    private AsyncTaskManager asyncTaskManager;

    @Override
    public void publish(Integer userId, SourceCodeRequest request) {
        User user = userService.selectById(userId);
        if (Objects.nonNull(user)) {
            if (user.getStatus().equals(UserStatusEnum.PROHIBIT.getCode())) {
                throw new BizException("账号已被封禁,请联系客服");
            }
        }
        if (StringUtils.isEmpty(request.getDescription())) {
            throw new BizException("请输入源码描述");
        }
        if (!user.getRegisterType().equals(UserTypeEnum.TECHNOLOGY_USER.getCode())) {
            throw new BizException("成为技术大牛才可以发布源码");
        }
        if (StringUtils.isEmpty(request.getTitle())) {
            throw new BizException("请输入源码标题");
        }
        if (CollectionUtils.isEmpty(request.getImages())) {
            throw new BizException("请选择系统源码图片");
        }
        if (Objects.isNull(request.getPrice())) {
            throw new BizException("请输入价格");
        }
        SourceCode sourceCode = new SourceCode();
        sourceCode.setPrice(request.getPrice());
        sourceCode.setDescription(request.getDescription());
        sourceCode.setUserId(userId);
        sourceCode.setTitle(request.getTitle());
        if (!CollectionUtils.isEmpty(request.getImages())) {
            sourceCode.setImages(JSONObject.toJSONString(request.getImages()));
        }
        if (Objects.nonNull(request.getTechTypeId())) {
            //技术类型
            sourceCode.setTechTypeId(request.getTechTypeId());
        }
        sourceCode.setStatus(SourceCodeStatusEnum.TO_VERIFY.getCode());
        sourceCode.setViewCount(NumberConstant.ZERO);
        save(sourceCode);
    }

    @Override
    public List<AppSourceCodeResponse> mineSourceCode(Integer userId) {
        LambdaQueryWrapper<SourceCode> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(SourceCode::getCreateTime);
        wrapper.eq(SourceCode::getUserId, userId);
        List<SourceCode> records = baseMapper.selectList(wrapper);
        if (!CollectionUtils.isEmpty(records)) {
            return records.stream().map(x -> {
                AppSourceCodeResponse response = new AppSourceCodeResponse();
                BeanUtils.copyProperties(x, response);
                if (StringUtils.isNotEmpty(x.getImages())) {
                    response.setImages(JSONObject.parseArray(x.getImages()).getString(0));
                }
                response.setCreateTime(DateUtils.localDateTime2DateStr(x.getCreateTime()));
                return response;
            }).collect(Collectors.toList());
        }
        return null;
    }

    @Override
    public List<SourceCodeListResponse> marketList(BasePageRequest request) {
        IPage<SourceCode> page = new Page<>(request.getPageNumber(), request.getPageSize());
        LambdaQueryWrapper<SourceCode> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(SourceCode::getCreateTime);
        wrapper.in(SourceCode::getStatus, Collections.singletonList(3));
        List<SourceCode> records = baseMapper.selectPage(page, wrapper).getRecords();
        if (!CollectionUtils.isEmpty(records)) {
            return records.stream().map(x -> {
                SourceCodeListResponse response = new SourceCodeListResponse();
                response.setId(x.getId());
                response.setTitle(x.getTitle());
                response.setImages(JSONObject.parseArray(x.getImages()).getString(0));
                response.setPrice(x.getPrice());
                response.setDescription(x.getDescription());
                response.setViewCount(x.getViewCount());
                response.setPublishTime(DateUtils.getDistanceTime(DateUtils.localDateTime2Date(x.getCreateTime()),
                        new Date()));
                response.setStatus(x.getStatus());
                response.setTechTypeName(techTypeService.detail(x.getTechTypeId()).getName());
                return response;
            }).collect(Collectors.toList());
        }
        return null;
    }

    @Override
    public void verifySourceCode(Integer sysUserId, SourceCodeVerifyRequest request) {
        SourceCode sourceCode = getById(request.getId());
        //审核通过
        if (request.getVerifyStatus().equals(AdminVerifyStatusEnum.VERIFY_PASS.getCode())) {
            if (Objects.nonNull(sourceCode)) {
                //修改状态
                sourceCode.setStatus(SourceCodeStatusEnum.VERIFY_PASS.getCode());
                updateById(sourceCode);
                //增加审核记录
                createVerifyRecord(sysUserId, request);
                //发送邮件
                asyncTaskManager.execute(() ->
                        sendDemandEmail(sourceCode.getUserId(), AdminVerifyStatusEnum.VERIFY_PASS.getCode(), null)
                );
            }
        } else {
            //不通过
            sourceCode.setStatus(DemandStatusEnum.VERIFY_REJECT.getCode());
            updateById(sourceCode);
            //增加审核记录
            createVerifyRecord(sysUserId, request);
            //发送邮件
            asyncTaskManager.execute(() -> {
                sendDemandEmail(sourceCode.getUserId(), AdminVerifyStatusEnum.VERIFY_REJECT.getCode(), request.getRemark());
            });
        }
    }

    @Override
    public AdminSourceCodeDetailResponse adminDetail(Integer id) {
        SourceCode sourceCode = baseMapper.selectById(id);
        if (Objects.isNull(sourceCode)) {
            throw new BizException("该源码已被删除");
        }
        AdminSourceCodeDetailResponse response = new AdminSourceCodeDetailResponse();
        BeanUtils.copyProperties(sourceCode, response);
        if (StringUtils.isNotEmpty(sourceCode.getImages())) {
            response.setImages(JSONObject.parseArray(sourceCode.getImages(), String.class));
        }

        //设置类型
        response.setTechTypeName(techTypeService.detail(sourceCode.getTechTypeId()).getName());
        //查询审核人
        AdminVerifyRecord verifyRecord = adminVerifyRecordService.getOne(new LambdaQueryWrapper<AdminVerifyRecord>().
                eq(AdminVerifyRecord::getDataId, sourceCode.getId()).eq(AdminVerifyRecord::getType, AdminVerifyTypeEnum.SOURCE_CODE_VERIFY.getCode()));
        if (Objects.nonNull(verifyRecord)) {
            SysUser sysUser = sysUserService.getById(verifyRecord.getSysUserId());
            response.setVerifyerName(sysUser.getNickname());
            response.setRemark(verifyRecord.getRemark());
        }
        return response;
    }


    /**
     * 发送邮件
     *
     * @param userId       用户ID
     * @param verifyStatus 审核状态
     */
    private void sendDemandEmail(Integer userId, Integer verifyStatus, String remark) {
        UserInfo userInfo = userInfoService.getOne(new LambdaQueryWrapper<UserInfo>().eq(UserInfo::getUserId, userId));
        if (Objects.nonNull(userInfo)) {
            if (verifyStatus.equals(AdminVerifyStatusEnum.VERIFY_PASS.getCode())) {
                mailService.sendMail(userInfo.getEmail(), String.format(EmailConstant.SOURCE_CODE_VERIFY_PASS, userInfo.getEmail()));
            } else {
                mailService.sendMail(userInfo.getEmail(), String.format(EmailConstant.SOURCE_CODE_VERIFY_REJECT, userInfo.getEmail(), remark));
            }
        }
    }

    /**
     * 增加审核记录
     *
     * @param request request
     */
    private void createVerifyRecord(Integer sysUserId, SourceCodeVerifyRequest request) {
        adminVerifyRecordService.save(request.getId(), sysUserId,
                request.getVerifyStatus(), request.getRemark(), AdminVerifyTypeEnum.SOURCE_CODE_VERIFY.getCode());
    }

    @Override
    public SourceCodeDetailResponse detail(Integer id) {
        SourceCode sourceCode = baseMapper.selectById(id);
        if (Objects.isNull(sourceCode)) {
            throw new BizException("该源码已被删除");
        }
        SourceCodeDetailResponse response = new SourceCodeDetailResponse();
        BeanUtils.copyProperties(sourceCode, response);
        if (StringUtils.isNotEmpty(sourceCode.getImages())) {
            response.setImages(JSONObject.parseArray(sourceCode.getImages(), String.class));
        }
        //设置类型
        response.setTechTypeName(techTypeService.detail(sourceCode.getTechTypeId()).getName());
        return response;
    }

    @Override
    public PageInfo<SourceCodeResponse> page(AdminSourceCodeRequest request) {

        IPage<SourceCode> page = new Page<>(request.getPageNumber(), request.getPageSize());
        LambdaQueryWrapper<SourceCode> wrapper = new LambdaQueryWrapper<>();
        if (Objects.nonNull(request.getTechTypeId())) {
            wrapper.eq(SourceCode::getTechTypeId, request.getTechTypeId());
        }
        if (StringUtils.isNotEmpty(request.getDescription())) {
            wrapper.like(SourceCode::getDescription, request.getDescription());
        }
        if (StringUtils.isNotEmpty(request.getTitle())) {
            wrapper.like(SourceCode::getTitle, request.getTitle());
        }
        if (Objects.nonNull(request.getStatus())) {
            wrapper.eq(SourceCode::getStatus, request.getStatus());
        }
        wrapper.orderByDesc(SourceCode::getCreateTime);
        List<SourceCode> records = baseMapper.selectPage(page, wrapper).getRecords();
        if (!CollectionUtils.isEmpty(records)) {
            List<SourceCodeResponse> list = records.stream().map(x -> {
                SourceCodeResponse response = new SourceCodeResponse();
                BeanUtils.copyProperties(x, response);
                User user = userService.selectById(x.getUserId());
                if (Objects.nonNull(user)) {
                    response.setAvatar(user.getAvatar());
                    response.setUsername(user.getNickname());
                }
                if (StringUtils.isNotEmpty(x.getImages())) {
                    response.setImages(JSONObject.parseArray(x.getImages()).getString(0));
                }
                TechType detail = techTypeService.detail(x.getTechTypeId());
                if (Objects.nonNull(detail)) {
                    response.setTechTypeName(detail.getName());
                }
                response.setCreateTime(DateUtils.localDateTime2Date(x.getCreateTime()));
                return response;
            }).collect(Collectors.toList());
            return new PageInfo<>(page.getTotal(), list);
        }
        return null;
    }

    @Override
    public Integer selectUserCodeCount(Integer userId) {
        return baseMapper.selectCount(new LambdaQueryWrapper<SourceCode>().eq(SourceCode::getUserId, userId));
    }

    @Override
    public void updateViewCount(Integer id) {
        SourceCode sourceCode = baseMapper.selectById(id);
        if (Objects.isNull(sourceCode)) {
            throw new BizException("该源码已被删除");
        }
        sourceCode.setViewCount(sourceCode.getViewCount() + 1);
        updateById(sourceCode);
    }

    @Override
    public void deleteSourceCode(Integer sourceCodeId, Integer userId) {
        baseMapper.delete(new LambdaQueryWrapper<SourceCode>().
                eq(SourceCode::getId, sourceCodeId).
                eq(SourceCode::getUserId, userId));
    }
}
